package com.tcm.smarthealth.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.smarthealth.common.exception.BusinessException;
import com.tcm.smarthealth.dto.UserLoginRequest;
import com.tcm.smarthealth.dto.UserLoginResponse;
import com.tcm.smarthealth.dto.UserProfileResponse;
import com.tcm.smarthealth.dto.UserRegisterRequest;
import com.tcm.smarthealth.entity.User;
import com.tcm.smarthealth.mapper.UserMapper;
import com.tcm.smarthealth.security.JwtTokenProvider;
import com.tcm.smarthealth.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;
import java.util.regex.Pattern;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private static final Pattern BCRYPT_PATTERN = Pattern.compile("\\A\\$2[aby]\\$\\d{2}\\$[./A-Za-z0-9]{53}\\z");

    private final JwtTokenProvider jwtTokenProvider;
    private final BCryptPasswordEncoder passwordEncoder;

    public UserServiceImpl(JwtTokenProvider jwtTokenProvider, BCryptPasswordEncoder passwordEncoder) {
        this.jwtTokenProvider = jwtTokenProvider;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(UserRegisterRequest request) {
        if (!Objects.equals(request.getPassword(), request.getConfirmPassword())) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "两次密码输入不一致");
        }

        boolean exists = lambdaQuery().eq(User::getUsername, request.getUsername()).exists();
        if (exists) {
            throw new BusinessException(HttpStatus.CONFLICT, "用户名已存在");
        }

        User user = new User();
        user.setUsername(request.getUsername().trim());
        user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
        user.setEmail(normalizeNullable(request.getEmail()));
        user.setPhone(normalizeNullable(request.getPhone()));
        user.setRole("USER");
        user.setStatus(1);

        save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserLoginResponse login(UserLoginRequest request) {
        String username = request.getUsername().trim();
        User user = lambdaQuery()
                .eq(User::getUsername, username)
                .one();

        if (user == null) {
            throw new BusinessException(HttpStatus.UNAUTHORIZED, "用户名或密码错误");
        }

        if (user.getStatus() != null && user.getStatus() == 0) {
            throw new BusinessException(HttpStatus.FORBIDDEN, "账户已禁用，请联系管理员");
        }

        boolean passwordMatches;
        String storedHash = user.getPasswordHash();

        if (isBcryptHash(storedHash)) {
            passwordMatches = passwordEncoder.matches(request.getPassword(), storedHash);
        } else {
            passwordMatches = Objects.equals(request.getPassword(), storedHash);
            if (passwordMatches) {
                user.setPasswordHash(passwordEncoder.encode(request.getPassword()));
            }
        }

        if (!passwordMatches) {
            throw new BusinessException(HttpStatus.UNAUTHORIZED, "用户名或密码错误");
        }

        user.setLastLoginAt(java.time.LocalDateTime.now());
        updateById(user);

        String token = jwtTokenProvider.generateToken(user.getId(), user.getUsername(), user.getRole());

        UserLoginResponse response = new UserLoginResponse();
        response.setToken(token);
        response.setTokenType("Bearer");
        response.setExpiresAt(jwtTokenProvider.getExpiryFromNow());
        response.setUser(convertToProfile(user));
        return response;
    }

    @Override
    public UserProfileResponse getProfile(Long userId) {
        User user = getById(userId);
        if (user == null) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "用户不存在");
        }
        return convertToProfile(user);
    }

    private UserProfileResponse convertToProfile(User user) {
        UserProfileResponse profile = new UserProfileResponse();
        BeanUtils.copyProperties(user, profile);
        return profile;
    }

    private String normalizeNullable(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private boolean isBcryptHash(String value) {
        return value != null && BCRYPT_PATTERN.matcher(value).matches();
    }

}

